/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Permissive License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Permissive License, please send an email to 
 * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Permissive License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Diagnostics;

using Microsoft.Scripting;
using Microsoft.Scripting.Internal;
using Microsoft.Scripting.Internal.Generation;
using Microsoft.Scripting.Math;


namespace Nua.Runtime
{
    class NuaTypeCustomizer : CoreReflectedTypeBuilder {
        private static MethodInfo[] _equalsHelper, _notEqualsHelper;
        private static Dictionary<DynamicType, Type> _inited = new Dictionary<DynamicType, Type>();

        private NuaTypeCustomizer(DynamicTypeBuilder builder) {
            Builder = builder;
        }

        public static void OnTypeInit(object sender, TypeCreatedEventArgs e) {
            DynamicType dt = e.Type;

            lock (_inited) {
                if (_inited.ContainsKey(dt) || ExtensionTypeAttribute.IsExtensionType(dt.UnderlyingSystemType)) {
                    return;
                }

                _inited[dt] = dt.UnderlyingSystemType;

#if DEBUG
                Dictionary<Type, Type> assertDict = new Dictionary<Type,Type>();
                foreach (KeyValuePair<DynamicType, Type> types in _inited) {
                    Debug.Assert(!assertDict.ContainsKey(types.Value));

                    assertDict[types.Value] = types.Value;
                }
#endif
            }

            NuaTypeCustomizer customizer = new NuaTypeCustomizer(DynamicTypeBuilder.GetBuilder(dt));
            
            customizer.AddOperators();

            //customizer.AddInitCode();
            //customizer.AddDocumentation();
            //customizer.AddOperators();
            //customizer.AddPythonProtocolMethods();
            //customizer.AddRichEqualityProtocols();
            //customizer.AddToStringProtocols();
            //if (ScriptDomainManager.Options.PrivateBinding) {
            //    customizer.AddPrivateMembers();
            //}

            //if (_sysTypes.ContainsKey(dt.UnderlyingSystemType)) {
            //    customizer.HideMembers();
            //}
        }

        private void AddOperators() 
        {
            Type sysType = Builder.UnfinishedType.UnderlyingSystemType;
            if (!sysType.IsPublic && !sysType.IsNestedPublic && !ScriptDomainManager.Options.PrivateBinding) return;

            BindingFlags bf = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

            foreach (MethodInfo mi in sysType.GetMethods(bf)) {
     
             
                    // we want to store a context sensitive version for system types (object, int, etc...)
                    // so that we hide the non-context sensitive version.
                    if (mi.IsStatic) {
                        StoreMethod(mi.Name, NuaContext.Context, mi, FunctionType.Function);
                    } else {
                        StoreMethod(mi.Name, NuaContext.Context, mi, FunctionType.Method);
                    }
               

                // TODO:// the reverse mappings here
            }

            if (sysType == typeof(Double))
            {
                StoreMethod("Add", NuaContext.Context, typeof(NuaOps).GetMethod("Add"), FunctionType.Function);
                StoreMethod("NuaEquals", NuaContext.Context, typeof(NuaOps).GetMethod("NuaEquals"), FunctionType.Function);
                StoreMethod("LessThan", NuaContext.Context, typeof(NuaOps).GetMethod("LessThan"), FunctionType.Function);
                StoreMethod("LessThanEquals", NuaContext.Context, typeof(NuaOps).GetMethod("LessThanEquals"), FunctionType.Function);
                StoreMethod("GreaterThan", NuaContext.Context, typeof(NuaOps).GetMethod("GreaterThan"), FunctionType.Function);
                StoreMethod("GreaterThanEquals", NuaContext.Context, typeof(NuaOps).GetMethod("GreaterThanEquals"), FunctionType.Function);

            }

        }

        protected override void AddImplicitConversion(MethodInfo mi) {
            throw new NotImplementedException();
        }


    }


}
